package com.zeny.express.framework.shared.serializer;

import java.util.Arrays;

import org.apache.commons.lang.SerializationException;
import org.codehaus.jackson.map.DeserializationConfig;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.annotate.JsonSerialize.Inclusion;
import org.codehaus.jackson.smile.SmileFactory;
import org.codehaus.jackson.type.TypeReference;

import com.zeny.express.framework.shared.exception.ApplicationException;
import com.zeny.express.framework.shared.util.ByteUtils;

public class JsonSerializer<T> implements Serializer<T> {

	private ObjectMapper objectMapper;

	/**
	 * 序列化类型
	 */
	private TypeReference<T> type;

	public JsonSerializer(boolean useBinary) {
		objectMapper = new ObjectMapper();

		if (useBinary) {
			objectMapper = new ObjectMapper(new SmileFactory());
		} else {
			objectMapper = new ObjectMapper();
		}

		// objectMapper.setDateFormat(new
		// SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"));
		objectMapper.setSerializationInclusion(Inclusion.NON_EMPTY);
		// 避免反序列化为科学计数法
		objectMapper.enable(DeserializationConfig.Feature.USE_BIG_DECIMAL_FOR_FLOATS);
		objectMapper.enable(DeserializationConfig.Feature.USE_BIG_INTEGER_FOR_INTS);
		
		objectMapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
	}

	/**
	 * 仅支持POJO CLASS
	 * @author zhuwei
	 * @date 2013年11月14日 下午3:00:13
	 */
	public JsonSerializer(boolean useBinary, Class<T> type) {
		this(useBinary);
		this.type = new TypeReference<T>(){};
	}

	/**
	 * 支持List<T> Map<String, T>等数据结构
	 * @author zhuwei
	 * @date 2013年11月14日 下午3:00:29
	 */
	public JsonSerializer(boolean useBinary, TypeReference<T> type) {
		this(useBinary);
		this.type = type;
	}

	public byte[] serialize(T t) throws SerializationException {
		if (t == null) {
			return new byte[0];
		}
		
		try {
			byte[] bytes = null;

			if (type != null) { // 类型不为空，直接序列化

				bytes = this.objectMapper.writer().writeValueAsBytes(t);

			} else { // 类型为空，序列化=类名长度+类名+数据

				/*byte[] clz = null;
				if (t instanceof Collection<?>) {
					Iterator<?> iter = ((Collection<?>)t).iterator();
					if (iter.hasNext()) {
						clz = iter.next().getClass().getName().getBytes();
					} else {
						clz = t.getClass().getName().getBytes();
					}
				} else {
					clz = t.getClass().getName().getBytes();
				}*/
				byte[] clz = t.getClass().getName().getBytes();
				byte[] len = ByteUtils.int2byte(clz.length);

				bytes = ByteUtils.concat(len, clz, this.objectMapper.writer()
						.writeValueAsBytes(t));
			}

			return bytes;

		} catch (Exception e) {
			throw new ApplicationException(ApplicationException.UNKNOWN, null);
		}
	}

	@SuppressWarnings("unchecked")
	public T deserialize(byte[] bytes) throws SerializationException {
		if (bytes == null || bytes.length == 0) {
			return null;
		}

		try {

			T t = null;

			if (type != null) {
				t = this.objectMapper.reader(type).readValue(bytes);
			} else {

				int len = ByteUtils.byte2int(Arrays.copyOf(bytes, 4));
				byte[] clz = Arrays.copyOfRange(bytes, 4, 4 + len);
				Class<?> type = Class.forName(new String(clz));

				t = (T) this.objectMapper.reader(type).readValue(bytes,
						4 + len, bytes.length - 4 - len);
			}

			return t;

		} catch (Exception e) {
			throw new ApplicationException(ApplicationException.UNKNOWN, null);
		}
	}
}